<html>
<head>
<meta charset="utf-8">
<title>json-compare</title>
<style>
body {
	padding: 0;
	margin: 0;
}
</style>
</head>
<div class="container"></div>
<script>
function Comparator(mode) {
    // container
    this.container = document.createElement('div');
    // inputContainer
    var inputContainer = document.createElement('div');
    var from = document.createElement('textarea');
    var to = document.createElement('textarea');
    var fromPrompt = document.createElement('div');
    var toPrompt = document.createElement('div');
    from.setAttribute('style', 'width: 50%; height: 330px; resize:none;');
    to.setAttribute('style', 'width: 50%; height: 330px; resize:none;');
    fromPrompt.setAttribute('style', 'width: 50%; color: red; display: inline-block;');
    toPrompt.setAttribute('style', 'width: 50%; color: red; display: inline-block;');
    // resultContainer
    var resultContainer = document.createElement('div');
    // 建立节点关系
    this.container.appendChild(inputContainer);
    this.container.appendChild(resultContainer);
    inputContainer.appendChild(from);
    inputContainer.appendChild(to);
    inputContainer.appendChild(fromPrompt);
    inputContainer.appendChild(toPrompt);

    // 类型获取
    function getType(o) {
        var str = Object.prototype.toString.call(o);
        return str.substring(8, str.length - 1);
    }

    // json解析器
    function JsonParser(json) {
        var _parse = function(tab, layer, o) {
            var type = getType(o);
            if (type == 'Object') {
                for (var field in o) {
                    _parse(tab, layer + '/' + field, o[field]);
                }
            } else if (type == 'Array') {
                for (var i = 0; i < o.length; i ++) {
                    _parse(tab, layer + '[' + i + ']', o[i]);
                }
            } else {
                tab[layer] = o;
            }
        }
        
        this.parse = function() {
            var tab = {};
            if (json) {
                try {
                    var jsonObj = JSON.parse(json);
                    _parse(tab, '', jsonObj);
                } catch (e) {
                    return false;
                }
            }
            return tab;
        }
    }

    // 比较条目
    function CompareEntry(op, key, value) {
        this.op = op;
        this.key = key;
        this.value = value;
    }

    // 比较方法
    function compare() {
        var fromValue = from.value;
        var toValue = to.value;
        var fromParser = new JsonParser(fromValue);
        var toParser = new JsonParser(toValue);
        var fromTab = fromParser.parse();
        var toTab = toParser.parse();
        if (!fromTab) {
            fromPrompt.innerHTML = 'json格式错误';
        } else {
            fromPrompt.innerHTML = '';
        }
        if (!toTab) {
            toPrompt.innerHTML = 'json格式错误';
        } else {
            toPrompt.innerHTML = '';
        }
        if (!fromTab || !toTab) {
            resultContainer.innerHTML = ''
            return;
        }
        var compares = [];
        var keySet = {};
        for (var fromK in fromTab) {
            keySet[fromK] = null;
        }
        for (var toK in toTab) {
            keySet[toK] = null;
        }
        for (var key in keySet) {
            var fromV = fromTab[key];
            var toV = toTab[key];
            if (fromV !== toV) {
                if (fromV == undefined) {
                    compares.push(new CompareEntry('+', key, toV));
                } else if (!toV) {
                    compares.push(new CompareEntry('-', key, fromV));
                } else {
                    compares.push(new CompareEntry('-', key, fromV));
                    compares.push(new CompareEntry('+', key, toV));
                }
            }
        }
        var init = '<table style="text-align: left;" border="1"><tr><th>change</th><th>type</th><th>path</th><th>value</th></tr>';
        var res = init;
        for (var i = 0; i < compares.length; i ++) {
            var compareEntry = compares[i];
            var color = '#B22222';// 红色
            if (compareEntry.op == '+') {
                color = '#006400';// 绿色
            }
            res += '<tr><td style="color:' + color + ';">' + compareEntry.op + '</td><td style="color:' + color + ';">' + getType(compareEntry.value)  + '</td><td style="color:' + color + ';">' + compareEntry.key + '</td><td style="color:' + color + ';">' + compareEntry.value + '</td></tr>';
        }
        if (res.length == init.length) {
            res = '';
        } else {
            res += '</table>';
        }
        resultContainer.innerHTML = res;
    }
    
    from.oninput = compare;
    to.oninput = compare;
    
    // 渲染
    this.render = function(dom) {
        dom && dom.appendChild(this.container);
    }
}
var comparator = new Comparator();
comparator.render(document.querySelector(".container"));
</script>
</html>